package com.hand.wfive.util.oss;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import com.alibaba.sdk.android.oss.ClientConfiguration;
import com.alibaba.sdk.android.oss.ClientException;
import com.alibaba.sdk.android.oss.OSS;
import com.alibaba.sdk.android.oss.OSSClient;
import com.alibaba.sdk.android.oss.ServiceException;
import com.alibaba.sdk.android.oss.callback.OSSCompletedCallback;
import com.alibaba.sdk.android.oss.common.OSSLog;
import com.alibaba.sdk.android.oss.common.auth.OSSCredentialProvider;
import com.alibaba.sdk.android.oss.common.auth.OSSPlainTextAKSKCredentialProvider;
import com.alibaba.sdk.android.oss.model.DeleteObjectRequest;
import com.alibaba.sdk.android.oss.model.DeleteObjectResult;
import com.alibaba.sdk.android.oss.model.GetObjectRequest;
import com.alibaba.sdk.android.oss.model.GetObjectResult;
import com.alibaba.sdk.android.oss.model.HeadObjectRequest;
import com.alibaba.sdk.android.oss.model.HeadObjectResult;
import com.alibaba.sdk.android.oss.model.PutObjectRequest;
import com.alibaba.sdk.android.oss.model.PutObjectResult;
import com.hand.wfive.App;
import com.hand.wfive.BuildConfig;
import com.hand.wfive.R;
import com.hand.wfive.entity.FileListModel;
import com.hand.wfive.entity.FileModel;
import com.hand.wfive.loginAndVip.ApiConfig;
import com.hand.wfive.loginAndVip.LoginConfig;
import com.hand.wfive.loginAndVip.UserManager;

import java.io.FileOutputStream;
import java.util.ArrayList;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.observers.ResourceObserver;
import rxhttp.wrapper.param.RxHttp;

public class OssRequest {

    private static final String TAG = OssRequest.class.getSimpleName();

    private static String accesskeyId = "";
    private static String secretkeyId = "";
    private static final String BUCKET = "e-signature";
    private static final String ENDPOINT = "http://oss-cn-hangzhou.aliyuncs.com";
    private static final int EXPIRATION_INTERVAL = 86400; //过期时间1天

    private final Handler mHandler = new Handler(Looper.getMainLooper());

    private final OSS oss;

    private void specialDo() {
        OssRequest.accesskeyId = App.getContext().getString(R.string.oss_key1);
        OssRequest.secretkeyId = App.getContext().getString(R.string.oss_key2);
        OssRequest.accesskeyId = OssRequest.accesskeyId.replace("29f", "");
        OssRequest.accesskeyId = OssRequest.accesskeyId.replace("uy7", "");
        OssRequest.secretkeyId = OssRequest.secretkeyId.replace("iu9", "");
        OssRequest.secretkeyId = OssRequest.secretkeyId.replace("Xds", "");
    }

    private OssRequest() {
        specialDo();
        OSSCredentialProvider credentialProvider =
                new OSSPlainTextAKSKCredentialProvider(accesskeyId, secretkeyId);
        ClientConfiguration config = new ClientConfiguration();
        config.setMaxErrorRetry(3);
        config.setConnectionTimeout(15 * 1000);
        config.setSocketTimeout(15 * 1000);
        config.setHttpDnsEnable(false);
        config.setCheckCRC64(true);
        oss = new OSSClient(App.getContext(), ENDPOINT, credentialProvider, config);
    }

    private static class SingleHolder {
        private static final OssRequest request = new OssRequest();
    }

    public static OssRequest getInstance() {
        return SingleHolder.request;
    }

    public String getFileUrl(String objectKey) {
        String url = null;
        try {
            if (existFile(objectKey))
                url = oss.presignConstrainedObjectURL(BUCKET, objectKey, EXPIRATION_INTERVAL);
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return url;
    }

    public boolean existFile(String objectKey) {
        try {
            //依次填写Bucket名称（例如examplebucket）和Object完整路径（例如exampledir/exampleobject.txt）。Object完整路径中不能包含Bucket名称。
            if (oss.doesObjectExist(BUCKET, objectKey)) {
                logD("object exist.");
                return true;
            } else {
                logD("object does not exist.");
            }
        } catch (ClientException e) {
            // 本地异常如网络异常等。
            e.printStackTrace();
        } catch (ServiceException e) {
            // 服务异常。
            e.printStackTrace();
            logD(e.getErrorCode());
            logD(e.getRequestId());
            logD(e.getHostId());
            logD(e.getRawMessage());
        }
        return false;
    }

    public void uploadFile(String objectKey, String uploadFilePath, OssCallBack callBack) {
        // 构造上传请求。
        // 依次填写Bucket名称（例如examplebucket）和Object完整路径（例如exampledir/exampleobject.txt）。
        // Object完整路径中不能包含Bucket名称。
        PutObjectRequest put = new PutObjectRequest(BUCKET, objectKey, uploadFilePath);
        // 异步上传时可以设置进度回调。
        put.setProgressCallback((request, currentSize, totalSize) ->
                logD("currentSize: " + currentSize + " totalSize: " + totalSize));
        oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {
            @Override
            public void onSuccess(PutObjectRequest request, PutObjectResult result) {
                logD("UploadSuccess");
                logD(result.getETag());
                logD(result.getRequestId());
                mHandler.postDelayed(() -> {
                    if (callBack != null) {
                        callBack.onSuccess();
                    }
                }, 200);
            }

            @Override
            public void onFailure(PutObjectRequest request, ClientException clientException,
                                  ServiceException serviceException) {
                // 请求异常。
                String msg = "请求异常！";
                if (clientException != null) {
                    // 客户端异常，例如网络异常等。
                    clientException.printStackTrace();
                    msg = "客户端异常，请检查网络是否正常！";
                }
                if (serviceException != null) {
                    // 服务端异常。
                    logD(serviceException.getErrorCode());
                    logD(serviceException.getRequestId());
                    logD(serviceException.getHostId());
                    logD(serviceException.getRawMessage());
                    msg = "服务端异常，请联系客服！";
                }
                String finalMsg = msg;
                mHandler.postDelayed(() -> {
                    if (callBack != null) {
                        callBack.onFailure(finalMsg);
                    }
                }, 200);
            }
        });
        // 取消上传任务。
        // task.cancel();
        // 等待上传任务完成。
        // task.waitUntilFinished();
    }

    public void uploadFile(FileModel model, OssCallBack callBack) {
        if (model.getFilePath().isEmpty() || model.getFileId().isEmpty()) {
            if (model.getCoverPath().isEmpty() || model.getCoverFileId().isEmpty()) {
                callBack.onFailure("无可上传内容");
            } else {
                uploadFileCover(model, callBack);
            }
            return;
        }

        uploadFile(model.getFileId(), model.getFilePath(), new OssCallBack() {
            @Override
            public void onSuccess() {
                if (model.getCoverPath().isEmpty() || model.getCoverFileId().isEmpty()) {
                    addCloudFile(model, callBack);
                } else {
                    uploadFileCover(model, callBack);
                }
            }

            @Override
            public void onFailure(String msg) {
                if (callBack != null) {
                    callBack.onFailure(msg);
                }
            }
        });
    }

    private void uploadFileCover(FileModel model, OssCallBack callBack) {
        uploadFile(model.getCoverFileId(), model.getCoverPath(), new OssCallBack() {
            @Override
            public void onSuccess() {
                addCloudFile(model, callBack);
            }

            @Override
            public void onFailure(String msg) {
                if (callBack != null) {
                    callBack.onFailure(msg);
                }
            }
        });
    }

    public void addCloudFile(FileModel model, OssCallBack callBack) {
        RxHttp.postForm(ApiConfig.addCloudFile)
                .add("appid", LoginConfig.AppId)
                .add("userId", UserManager.getInstance().getUserId())
                .add("size", model.getSize())
                .add("type", model.getType())
                .add("status", model.getStatus())
                .add("fileId", model.getFileId())
                .add("fileName", model.getFileName())
                .add("coverFileId", model.getCoverFileId())
                .asClass(FileListModel.class)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new ResourceObserver<FileListModel>() {
                    @Override
                    public void onNext(FileListModel fileListModel) {
                        if (fileListModel.getCode() == ApiConfig.SUCCESSCODE) {
                            callBack.onSuccess();
                        } else {
                            callBack.onFailure(fileListModel.getMsg());
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        callBack.onFailure("");
                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

    public void dowloadFile(String objectKey, String downloadFilePath, OssCallBack callBack) {
        // 构造下载文件请求。
        // 依次填写Bucket名称（例如examplebucket）和Object完整路径（例如exampledir/exampleobject.txt）。Object完整路径中不能包含Bucket名称。
        GetObjectRequest get = new GetObjectRequest(BUCKET, objectKey);
        oss.asyncGetObject(get, new OSSCompletedCallback<GetObjectRequest, GetObjectResult>() {
            @Override
            public void onSuccess(GetObjectRequest request, GetObjectResult result) {
                // 开始读取数据。
                long length = result.getContentLength();
                if (length > 0) {
                    byte[] buffer = new byte[(int) length];
                    int readCount = 0;
                    while (readCount < length) {
                        try {
                            readCount += result.getObjectContent().read(buffer, readCount, (int) length - readCount);
                        } catch (Exception e) {
                            e.printStackTrace();
                            OSSLog.logInfo(e.toString());
                        }
                    }
                    // 将下载后的文件存放在指定的本地路径，例如D:\\localpath\\exampleobject.jpg。
                    try {
                        FileOutputStream fout = new FileOutputStream(downloadFilePath);
                        fout.write(buffer);
                        fout.close();
                        mHandler.postDelayed(() -> {
                            if (callBack != null) {
                                callBack.onSuccess();
                            }
                        }, 200);
                    } catch (Exception e) {
                        e.printStackTrace();
                        OSSLog.logInfo(e.toString());
                        mHandler.postDelayed(() -> {
                            if (callBack != null) {
                                callBack.onFailure("下载云文件到本地保存失败！");
                            }
                        }, 200);
                    }
                } else {
                    mHandler.postDelayed(() -> {
                        if (callBack != null) {
                            callBack.onFailure("下载云文件失败！");
                        }
                    }, 200);
                }
            }

            @Override
            public void onFailure(GetObjectRequest request, ClientException clientException,
                                  ServiceException serviceException) {
                // 请求异常。
                String msg = "请求异常！";
                if (clientException != null) {
                    // 客户端异常，例如网络异常等。
                    clientException.printStackTrace();
                    msg = "客户端异常，请检查网络是否正常！";
                }
                if (serviceException != null) {
                    // 服务端异常。
                    logD(serviceException.getErrorCode());
                    logD(serviceException.getRequestId());
                    logD(serviceException.getHostId());
                    logD(serviceException.getRawMessage());
                    msg = "服务端异常，请联系客服！";
                }
                String finalMsg = msg;
                mHandler.postDelayed(() -> {
                    if (callBack != null) {
                        callBack.onFailure(finalMsg);
                    }
                }, 200);
            }
        });
    }

    public void deleteFile(String objectKey, OssCallBack callBack) {
        if (TextUtils.isEmpty(objectKey) || !existFile(objectKey)) {
            if (callBack != null) {
                callBack.onSuccess();
            }
            return;
        }
        // 创建删除请求。
        // 依次填写Bucket名称（例如examplebucket）和Object完整路径（例如exampledir/exampleobject.txt）。Object完整路径中不能包含Bucket名称。
        DeleteObjectRequest delete = new DeleteObjectRequest(BUCKET, objectKey);
        // 异步删除。
        oss.asyncDeleteObject(delete, new OSSCompletedCallback<DeleteObjectRequest, DeleteObjectResult>() {
            @Override
            public void onSuccess(DeleteObjectRequest request, DeleteObjectResult result) {
                logD("success!");
                mHandler.postDelayed(() -> {
                    if (callBack != null) {
                        callBack.onSuccess();
                    }
                }, 200);
            }

            @Override
            public void onFailure(DeleteObjectRequest request, ClientException clientException, ServiceException serviceException) {
                // 请求异常。
                String msg = "请求异常！";
                if (clientException != null) {
                    // 客户端异常，例如网络异常等。
                    clientException.printStackTrace();
                    msg = "客户端异常，请检查网络是否正常！";
                }
                if (serviceException != null) {
                    // 服务端异常。
                    logD(serviceException.getErrorCode());
                    logD(serviceException.getRequestId());
                    logD(serviceException.getHostId());
                    logD(serviceException.getRawMessage());
                    msg = "服务端异常，请联系客服！";
                }
                String finalMsg = msg;
                mHandler.postDelayed(() -> {
                    if (callBack != null) {
                        callBack.onFailure(finalMsg);
                    }
                }, 200);
            }
        });
    }

    public void delCloudFile(FileModel model, OssCallBack callBack) {
        delCloudFile(model, new ArrayList<>(), callBack);
    }

    public void delCloudFile(FileModel model, ArrayList<String> excludeData, OssCallBack callBack) {
        RxHttp.postForm(ApiConfig.delCloudFile)
                .add("appid", LoginConfig.AppId)
                .add("userId", UserManager.getInstance().getUserId())
                .add("fileId", model.getFileId())
                .asClass(FileListModel.class)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new ResourceObserver<FileListModel>() {
                    @Override
                    public void onNext(@NonNull FileListModel fileListModel) {
                        if (fileListModel.getCode() == ApiConfig.SUCCESSCODE) {
                            if (model.getFileId().contains(",")) {
                                String[] fileIds = model.getFileId().split(",");
                                for (String fileId : fileIds) {
                                    if (!excludeData.contains(fileId)) {
                                        deleteFile(fileId, null);
                                    }
                                }
                            } else if (!excludeData.contains(model.getFileId())) {
                                deleteFile(model.getFileId(), null);
                            }
                            if (!TextUtils.isEmpty(model.getCoverFileId()) &&
                                    !excludeData.contains(model.getCoverFileId())) {
                                deleteFile(model.getCoverFileId(), null);
                            }
                            if (callBack != null) {
                                callBack.onSuccess();
                            }
                        } else {
                            if (callBack != null) {
                                callBack.onFailure(fileListModel.getMsg());
                            }
                        }
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        if (callBack != null) {
                            callBack.onFailure("删除失败，请稍后重试");
                        }
                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

    public void renameFile(FileModel model, String newName, OssCallBack callBack) {
        RxHttp.postForm(ApiConfig.addCloudFile)
                .add("appid", LoginConfig.AppId)
                .add("userId", UserManager.getInstance().getUserId())
                .add("fileId", model.getFileId())
                .add("fileName", newName)
                .asClass(FileListModel.class)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new ResourceObserver<FileListModel>() {
                    @Override
                    public void onNext(@NonNull FileListModel fileListModel) {
                        if (fileListModel.getCode() == ApiConfig.SUCCESSCODE) {
                            if (callBack != null) {
                                callBack.onSuccess();
                            }
                        }
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        if (callBack != null) {
                            callBack.onFailure("修改失败，请稍后重试");
                        }
                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

    public void getFileMetadata(String objectKey, OssMetadataCallBack callBack) {
        // 创建同步获取文件元信息请求。
        // 依次填写Bucket名称（例如examplebucket）和Object完整路径（例如exampledir/exampleobject.txt）。Object完整路径中不能包含Bucket名称。
        HeadObjectRequest head = new HeadObjectRequest(BUCKET, objectKey);
        // 获取文件元信息。
        oss.asyncHeadObject(head, new OSSCompletedCallback<HeadObjectRequest, HeadObjectResult>() {
            @Override
            public void onSuccess(HeadObjectRequest request, HeadObjectResult result) {
                // 获取文件长度。
                logD("object Size: " + result.getMetadata().getContentLength());
                // 获取文件类型。
                logD("object Content Type: " + result.getMetadata().getContentType());
                mHandler.postDelayed(() -> {
                    if (callBack != null) {
                        callBack.onSuccess(result.getMetadata());
                    }
                }, 200);
            }

            @Override
            public void onFailure(HeadObjectRequest request, ClientException clientException, ServiceException serviceException) {
                // 请求异常。
                String msg = "请求异常！";
                if (clientException != null) {
                    // 客户端异常，例如网络异常等。
                    clientException.printStackTrace();
                    msg = "客户端异常，请检查网络是否正常！";
                }
                if (serviceException != null) {
                    // 服务端异常。
                    logD(serviceException.getErrorCode());
                    logD(serviceException.getRequestId());
                    logD(serviceException.getHostId());
                    logD(serviceException.getRawMessage());
                    msg = "服务端异常，请联系客服！";
                }
                String finalMsg = msg;
                mHandler.postDelayed(() -> {
                    if (callBack != null) {
                        callBack.onFailure(finalMsg);
                    }
                }, 200);
            }
        });
        // task.waitUntilFinished(); //等待任务完成。
    }

    private void logD(String msg) {
        if (TextUtils.isEmpty(msg)) return;
        if (BuildConfig.DEBUG) Log.d(TAG, msg);
    }
}
